﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.Net.TCP
{
    public class TCPClient
    {
        private IPEndPoint _serEndPoint;

        /// <summary>
        /// 用于通讯的套接字
        /// </summary>
        public Socket Socket;
        private TCPClientReceiveThread _recvThread;
        public IResponseHandlerFactory ResponseHandlerFactory { get; private set; }

        /// <summary>
        /// 心跳线程
        /// </summary>
        private TCPHeartbeatThread _heartbeatThread;

        /// <summary>
        /// 最后的活跃时间
        /// </summary>
        public long LatestActiveTicks { get; set; }

        public TCPConnectState ConnectState { get; set; }

        byte[] _receiveBuffer;
        private NetBufferPool _netBufferPool;
        private bool _isReceiving;

        #region reconnect thread
        TCPReconnectThread _reconnectThread;
        #endregion

        /// <summary>
        /// 登录之后在服务器的ID信息
        /// </summary>
        public uint ID { get; set; }

        #region constractor

        /// <summary>
        /// 构造tcp客户端
        /// </summary>
        /// <param name="responseHandlerFactory">用于创建处理接口的工厂实例</param>
        public TCPClient(IResponseHandlerFactory responseHandlerFactory)
        {
            ResponseHandlerFactory = responseHandlerFactory;

            ConnectState = TCPConnectState.Initiated;

            // 8k
            _receiveBuffer = new byte[8 * 1024];
            _netBufferPool = new NetBufferPool();
        }

        #endregion

        #region connect
        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="ip">服务器地址</param>
        /// <param name="port">端口</param>
        /// <exception cref="Exception"></exception>
        public void Connect(string ip, int port)
        {
            if (ConnectState == TCPConnectState.Connected)
            {
                // 已连接
                return;
            }

            Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Socket.SendBufferSize = 8 * 1024;
            Socket.ReceiveBufferSize = 8 * 1024;
            IPAddress address = IPAddress.Parse(ip);
            _serEndPoint = new IPEndPoint(address, port);
            try
            {
                Socket.Connect(_serEndPoint);
                // 发送登录信息
                // 获取登录信息
                SendConnectData();
                ConnectState = TCPConnectState.Connected;
            }
            catch (Exception ex)
            {
                OnDisconnectError();
                throw ex;
            }

            if (ConnectState == TCPConnectState.Connected)
            {
                _recvThread = new TCPClientReceiveThread(this);

                _recvThread.Start();
            }
        }

        /// <summary>
        /// 重新连接
        /// </summary>
        /// <exception cref="Exception"></exception>
        public void Reconnect()
        {
            if (ConnectState == TCPConnectState.Connected)
            {
                return;
            }

            try
            {
                if (Socket != null)
                {
                    Socket.Close();
                    Socket = null;
                }
                Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                Socket.Connect(_serEndPoint);
                // 发送登录信息
                // 获取登录信息
                SendConnectData();
                ConnectState = TCPConnectState.Connected;
            }
            catch (Exception ex)
            {
                ConnectState = TCPConnectState.Disconnected;
                throw ex;
            }

            if (ConnectState == TCPConnectState.Connected)
            {
                if (_recvThread == null)
                {
                    _recvThread = new TCPClientReceiveThread(this);
                }
                _recvThread.Start();
            }
        }

        private void SendConnectData()
        {
            NetPackage package = NetPackage.BuildSysPackage(NetSysCommand.Connect, NetReplayMode.Self, 0, new byte[] { 0x05 });
            Send(package);
            NetPackage loginPackage = Receive();
        }
        #endregion

        #region disconnect
        public int DisConnect()
        {
            if (_recvThread != null)
            {
                _recvThread.Stop();
            }

            if (Socket != null)
            {
                try
                {
                    SendDisconnectData();
                    // 发送一个退出的数据到服务器
                    Socket.Disconnect(false);
                }
                catch (Exception ex)
                {
                }
            }

            OnDisconnect();
            return 0;
        }

        private void SendDisconnectData()
        {
            NetPackage package = NetPackage.BuildSysPackage(NetSysCommand.Disconnect, NetReplayMode.None, 0, new byte[] { 0x05 });
            Send(package);
        }
        #endregion

        #region receive Data

        /// <summary>
        /// 接收数据
        /// </summary>
        public NetPackage Receive()
        {
            try
            {
                int receiveLen = Socket.Receive(_receiveBuffer, 0, _receiveBuffer.Length, SocketFlags.None);
                if (receiveLen > 0)
                {
                    _netBufferPool.AppendBuffer(_receiveBuffer, receiveLen);

                    NetPackage netBuffer = _netBufferPool.GetNetBuffer();
                    return netBuffer;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("接收数据出错,ex:{0}", ex));
                OnDisconnectError();
            }
            return null;
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        public void ReceiveAsync()
        {
            try
            {
                if (!_isReceiving)
                {
                    _isReceiving = true;
                    Socket.BeginReceive(_receiveBuffer, 0, _receiveBuffer.Length, SocketFlags.None, new AsyncCallback(OnReceiveCallback), null);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("接收数据出错,ex:{0}", ex));
                OnDisconnectError();
            }
        }

        private void OnReceiveCallback(IAsyncResult ar)
        {
            try
            {
                int receiveLen = Socket.EndReceive(ar);
                if (receiveLen > 0)
                {
                    _netBufferPool.AppendBuffer(_receiveBuffer, receiveLen);

                    NetPackage netBuffer = _netBufferPool.GetNetBuffer();
                    if (netBuffer != null)
                    {
                        IResponseHandler handler = ResponseHandlerFactory.Create(netBuffer.Command);
                        handler.Handle(netBuffer);
                    }
                }
            }
            catch (Exception ex)
            {
            }
            _isReceiving = false;
        }
        #endregion

        public void Send(NetPackage buffer)
        {
            try
            {
                int len = Socket.Send(buffer.Buffer);
                while (len < buffer.Buffer.Length)
                {
                    System.Diagnostics.Debug.WriteLineIf(len < buffer.Buffer.Length, "发送的数据长度小于实际的数据长度,继续发送");
                    len += Socket.Send(buffer.Buffer, len, buffer.Buffer.Length - len, SocketFlags.None);
                }

                LatestActiveTicks = DateTime.Now.Ticks;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("发送数据出错,ex:{0}", ex));
                OnDisconnectError();
            }
        }

        #region
        //private void Send(byte[] buffer, int length)
        //{
        //    //_clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(OnSendCallback), null);
        //    try
        //    {
        //        //_clientSocket.Send(buffer,);
        //        Socket.BeginSend(buffer, 0, length, SocketFlags.None, new AsyncCallback(OnSendCallback), null);
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }
        //}


        //void OnSendCallback(IAsyncResult ar)
        //{
        //    Socket.EndSend(ar);
        //}
        #endregion

        /// <summary>
        /// 出错时，和服务器断开连接
        /// </summary>
        private void OnDisconnectError()
        {
            ConnectState = TCPConnectState.Disconnected;
            if (_reconnectThread == null)
            {
                _reconnectThread = new TCPReconnectThread(this);
            }

            _reconnectThread.Start();
        }
        private void OnDisconnect()
        {
            ConnectState = TCPConnectState.Disconnected;
        }
    }
}
